//////////////////////////////////////
// Fast Container Library           //
// MIT License - Copyright (c) 2012 //
//////////////////////////////////////

#pragma once

#include "common.h"
#include "allocator.h"
#include "virtual_allocator.h"

FC_NAMESPACE_BEGIN


/*
 * @stl_allocator
 * stl compatible allocator model.
 * allocates memory using the default fc allocation methods, and can be used
 * as a base class for interfacing between stl containers and allocators.
 */
template <class T>
class stl_allocator
{
public:
	typedef T					value_type;
	typedef value_type*			pointer;
	typedef const value_type*	const_pointer;
	typedef value_type&			reference;
	typedef const value_type&	const_reference;
	typedef size_t				size_type;
	typedef ptrdiff_t			difference_type;

	enum
	{
		type_alignment = FC_ALIGNOF(T),
		type_alignment_offset = 0
	};

	template <class U>
	struct rebind { typedef stl_allocator<U> other; };

	pointer address( reference value ) const				{ return &value; }
	const_pointer address( const_reference value ) const	{ return &value; }

	T* allocate( size_t n, const_pointer = 0 )
	{
		return (T*)fc::allocate(n * sizeof(T));
	}

	void deallocate( pointer ptr, size_t )
	{
		fc::deallocate(ptr);
	}

	void construct( pointer ptr, const T& value = T() ) { fc::construct( ptr, value ); }
	void destroy( pointer ptr ) { fc::destroy( ptr ); }

	size_t max_size() const
	{
		return (size_t(-1) / sizeof(T));
	}

	template <class U> bool operator ==( const stl_allocator<U>& ) const { return true; }
	template <class U> bool operator !=( const stl_allocator<U>& a ) const { return !(a == *this); }

};


/*
 * @stl_polymorphic_allocator
 * stl compatible allocator model that holds an underlying pointer
 * to a fc::allocator type.
 */
template <class T>
class stl_polymorphic_allocator : public stl_allocator<T>
{
	typedef T					value_type;
	typedef value_type*			pointer;
	typedef const value_type*	const_pointer;
	typedef value_type&			reference;
	typedef const value_type&	const_reference;
	typedef size_t				size_type;
	typedef ptrdiff_t			difference_type;
	typedef stl_allocator<T>	base_type;

	template <class U>
	struct rebind { typedef stl_polymorphic_allocator<U> other; };

	stl_polymorphic_allocator() : m_allocator() {}
	explicit stl_polymorphic_allocator( allocator* alloc ) : m_allocator(alloc) {}

	void set_allocator( allocator* alloc ) { m_allocator = alloc; }
	allocator* get_allocator() const { return m_allocator; }

	T* allocate( size_t n, const_pointer = 0 )
	{
		FC_ASSERT(m_allocator);
		return (T*)m_allocator->allocate(n * sizeof(T));
	}

	void deallocate( pointer ptr )
	{
		FC_ASSERT(m_allocator);
		m_allocator->deallocate(ptr);
	}

	template <class U> bool operator ==( const stl_polymorphic_allocator<U>& a ) const
	{ return *get_allocator() == *a.get_allocator(); }

	template <class U> bool operator !=( const stl_polymorphic_allocator<U>& a ) const
	{ return !(a == *this); }

protected:
	allocator* m_allocator;

};



FC_NAMESPACE_END
